package io.kiki.sba.registry.server.metadata.slot.util;


import io.kiki.sba.registry.server.metadata.slot.assigner.ScoreStrategy;

import java.util.*;


public class MigratableSlotInfo {

    /**
     * slotId
     */
    private final Set<Integer> leaderSlotIdSet = new HashSet<>();
    /**
     * key: slotId, value: counter (one slot could has multi followers to migrate)
     */
    private final Map<Integer, Integer> lackFollowers = new HashMap<>();

    /**
     * Add leader migrate slot group.
     */
    public MigratableSlotInfo addLeaderSlotId(int slotId) {
        leaderSlotIdSet.add(slotId);
        return this;
    }

    public boolean isEmpty() {
        return leaderSlotIdSet.isEmpty() && lackFollowers.isEmpty();
    }

    /**
     * Add follower migrate slot group.
     */
    public MigratableSlotInfo addLackFollowerNum(int slotId) {
        lackFollowers.put(slotId, lackFollowers.getOrDefault(slotId, 0) + 1);
        return this;
    }

    public MigratableSlotInfo addLackFollowerNum(int slotId, int num) {
        lackFollowers.put(slotId, lackFollowers.getOrDefault(slotId, 0) + num);
        return this;
    }

    public List<Integer> getLeadersByScore(ScoreStrategy<Integer> scoreStrategy) {
        List<Integer> list = new ArrayList<>(this.leaderSlotIdSet);
        list.sort(new Comparator<Integer>() {
            @Override
            public int compare(Integer slotId1, Integer slotId2) {
                return scoreStrategy.score(slotId1) - scoreStrategy.score(slotId2);
            }
        });
        return list;
    }

    public List<FollowerToAssign> getFollowersByScore(ScoreStrategy<FollowerToAssign> scoreStrategy) {
        List<FollowerToAssign> list = new ArrayList<>();
        lackFollowers.forEach((slotId, nums) -> list.add(new FollowerToAssign(slotId, nums)));
        list.sort(new Comparator<FollowerToAssign>() {
            @Override
            public int compare(FollowerToAssign o1, FollowerToAssign o2) {
                return scoreStrategy.score(o1) - scoreStrategy.score(o2);
            }
        });
        return list;
    }


    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;
        MigratableSlotInfo that = (MigratableSlotInfo) o;
        return Objects.equals(leaderSlotIdSet, that.leaderSlotIdSet) && Objects.equals(lackFollowers, that.lackFollowers);
    }

    @Override
    public int hashCode() {
        return Objects.hash(leaderSlotIdSet, lackFollowers);
    }


}
